/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.healthecology.module;

import com.huawei.healthecology.json.GsonMapper;
import com.huawei.healthecology.json.JsonMapper;
import com.huawei.healthecology.json.JsonMapperType;
import com.huawei.healthecology.processor.BleCentralProcessor;
import com.huawei.healthecology.processor.BleGattProcessor;
import com.huawei.healthecology.processor.BluetoothCentralProcessor;
import com.huawei.healthecology.processor.HttpClientProcessor;
import com.huawei.healthecology.processor.WifiDeviceProcessor;

import ohos.app.Context;
import okhttp3.OkHttpClient;

import java.util.Optional;

/**
 * Client module
 */
public class ClientModule {
    private static JsonModule jsonModule;

    private static BleGattProcessor bleGattProcessor;

    private static BleCentralProcessor bleCentralProcessor;

    private static WifiDeviceProcessor wifiDeviceProcessor;

    private static BluetoothCentralProcessor bluetoothCentralProcessor;

    private static HttpClientProcessor httpRequestProcessor;

    private ClientModule() {
    }

    /**
     * Inject context, and initialize the client module
     *
     * @param context Context
     */
    public static void inject(Context context) {
        jsonModule = JsonModule.init(GsonMapper.get());
        bleGattProcessor = BleGattProcessor.get();
        bleCentralProcessor = BleCentralProcessor
            .builder(context).build();
        bluetoothCentralProcessor = BluetoothCentralProcessor
            .builder(context).build();
        wifiDeviceProcessor = WifiDeviceProcessor
            .builder(context).build();
        httpRequestProcessor = HttpClientProcessor.builder()
            .httpClient(new OkHttpClient())
            .jsonMapper(GsonMapper.get()).build();
        bleGattProcessor.initProcessor();
        bleCentralProcessor.initProcessor();
        wifiDeviceProcessor.initProcessor();
        httpRequestProcessor.initProcessor();
        bluetoothCentralProcessor.initProcessor();
    }

    /**
     * Gets parser if it is available
     *
     * @return The Json parser
     */
    public static Optional<JsonMapper> getParser() {
        return Optional.ofNullable(jsonModule).map(JsonModule::getMapper);
    }

    /**
     * Get Ble gatt processor if it is available
     *
     * @return BleGattProcessor gatt processor
     */
    public static Optional<BleGattProcessor> getGattProcessor() {
        return Optional.ofNullable(bleGattProcessor);
    }

    /**
     * Gets Ble central processor if it is available
     *
     * @return The ble central processor
     */
    public static Optional<BleCentralProcessor> getBleCentralProcessor() {
        return Optional.ofNullable(bleCentralProcessor);
    }

    /**
     * Gets Bluetooth central processor if it is available
     *
     * @return The bluetooth central processor
     */
    public static Optional<BluetoothCentralProcessor> getBluetoothCentralProcessor() {
        return Optional.ofNullable(bluetoothCentralProcessor);
    }

    /**
     * Gets Wi-Fi device processor if it is available
     *
     * @return The Wi-Fi device processor
     */
    public static Optional<WifiDeviceProcessor> getWifiDeviceProcessor() {
        return Optional.ofNullable(wifiDeviceProcessor);
    }

    /**
     * Gets http client processor if it is available.
     *
     * @return The http client processor
     */
    public static Optional<HttpClientProcessor> getHttpProcessor() {
        return Optional.ofNullable(httpRequestProcessor);
    }

    /**
     * Config Json mapper with the given mapper type
     *
     * @param mapperType Json mapper type
     */
    public static void configJsonMapper(JsonMapperType mapperType) {
        jsonModule = Optional.ofNullable(mapperType)
            .map(type -> JsonModule.init(type.getMapper()))
            .orElse(JsonModule.init(GsonMapper.get()));
    }

    /**
     * Destroy allocations, and {@link ClientModule#inject(Context)} needs to call again before other methods
     */
    public static void destroy() {
        release();
        bleGattProcessor.destroyProcessor();
        bleCentralProcessor.destroyProcessor();
        wifiDeviceProcessor.destroyProcessor();
        httpRequestProcessor.destroyProcessor();
        bluetoothCentralProcessor.destroyProcessor();
        jsonModule = null;
        bleGattProcessor = null;
        bleCentralProcessor = null;
        wifiDeviceProcessor = null;
        httpRequestProcessor = null;
        bluetoothCentralProcessor = null;
    }

    /**
     * To clean up resources. Calling this method would not require inject module again
     */
    public static void release() {
        bleGattProcessor.releaseResource();
        bleCentralProcessor.releaseResource();
        wifiDeviceProcessor.releaseResource();
        httpRequestProcessor.releaseResource();
        bluetoothCentralProcessor.releaseResource();
    }
}
